package com.moonshineproject.plugin.actionscript.as3parser.parsers
{
	import com.moonshineproject.plugin.actionscript.as3parser.MetadataManager;
	import com.moonshineproject.plugin.actionscript.as3parser.vo.ClassVO;
	import com.moonshineproject.plugin.actionscript.as3parser.vo.PackageVO;
	
	import flash.filesystem.File;
	import flash.utils.Dictionary;
	
	import org.as3commons.asblocks.parser.api.IParserNode;

	public class ImportParser
	{
		public var packageName:String = "";
		public var packagePath:String = "";

		protected var directoryFileCache:Dictionary = new Dictionary(true);

		protected var metadata:MetadataManager;
		
		protected var ast:IParserNode;		
		protected var sourceDirectories:Vector.<File>;
		
		protected var imports:Dictionary = new Dictionary();
		protected var importPositions:Array = [];

		protected var packageNode:IParserNode;


		public function ImportParser(ast:IParserNode, metadata:MetadataManager, sourceDir:Vector.<File>)
		{
			this.ast = ast;
			this.metadata = metadata;
			this.sourceDirectories = sourceDir;
		}

		public function resolveImports():void
		{
			recurseResolveImports(ast);
		}
		
		public function get lastImportLineIdx():int
		{
			if (importPositions.length)
			{
				return importPositions[importPositions.length-1];	
			}	
			else if (packageNode)
			{
				if (!packageNode.children) return -1;
				
				for each (var node:IParserNode in packageNode.children)
				{
					if (node.kind == "content")
					{
						return node.line;
					}
				}
			}
			
			return -1;
		}


		public function getClassPathForType(type:String):String
		{
			var pkgn:Array = imports[type];
			if (pkgn)
			{
				return pkgn.join(File.separator);
			}
			else
			{
				if (isTypeInPackage(type))
				{
					return packagePath;
				}
			}

			return null;
		}

		public function getPackageNameForType(type:String):String
		{
			var pkgn:Array = imports[type];
			if (pkgn)
			{
				return pkgn.join(".");
			}
			else
			{
				if (isTypeInPackage(type))
				{
					return packageName;
				}
			}

			return null;
		}
		
		protected function isTypeInPackage(type:String):Boolean
		{
			var listing:Array
			// TODO: Use cache layer instead of this
			// Look for files in the same directory that might match
			for each (var sourceDir:File in sourceDirectories)
			{
				if (directoryFileCache[sourceDir])
				{
					listing = directoryFileCache[sourceDir];
				}
				else
				{
					var dir:File = sourceDir.resolvePath(packagePath);
					if (!dir.exists)
						continue;
					listing = directoryFileCache[sourceDir] = dir.getDirectoryListing();

				}
				for each (var file:File in listing)
				{
					var split:Array = file.name.split(".");
					if (split.length > 1)
					{
						var name:String = split[0];
						if (name == type)
						{
							return true;
						}
					}
				}
			}

			return false;
		}

		protected function recurseResolveImports(searchNode:IParserNode):void
		{
			if (!searchNode.children)
				return;

			for (var i:int = 0; i < searchNode.children.length; i++)
			{
				var node:IParserNode = searchNode.children[i];
				if (node.kind == "content")
				{
					recurseResolveImports(node);
					return;
				}
				else if (node.kind == "package")
				{
					findPackage(node);
					recurseResolveImports(node);
					packageNode = node;
					return;
				}
				else if (node.kind == "import")
				{
					recurseResolveImports(node);
					saveImportLine(node);
				}
				else if (node.kind == "type")
				{
					addTypeImport(node.stringValue);
					return;
				}
			}
		}

		protected function saveImportLine(node:IParserNode):void
		{
			importPositions.push(node.line);
		}

		// Find this files package statement
		protected function findPackage(searchNode:IParserNode):void
		{
			if (!searchNode.children)
				return;

			for (var i:int = 0; i < searchNode.children.length; i++)
			{
				var node:IParserNode = searchNode.children[i];
				if (node.kind == "name")
				{
					this.packageName = node.stringValue;
					this.packagePath = AS3ParserUtil.packageNameToPath(packageName);
				}
			}
		}

		protected function addTypeImport(str:String):void
		{
			var split:Array = str.split(".");
			var type:String = split[split.length - 1];

			if (type == "*")
			{
				// Dive down & find that package
				if (split.length > 1)
				{
					split.pop();
					handleStarImport(split);
				}
				else
				{
					// Just add all global classes (shouldn't be very common)
					addStarImports(metadata.globalPackageCache);
				}
			}
			else
			{
				imports[type] = split.slice(0, split.length - 1);
			}
		}
		
		protected function handleStarImport(pkgs:Array):void
		{
			var currentPackage:PackageVO = metadata.globalPackageCache;
			
			for each (var name:String in pkgs)
			{
				currentPackage = currentPackage.getPackage(name);
				if (!currentPackage) return;
			}
			
			addStarImports(currentPackage);
		}
		
		protected function addStarImports(pkg:PackageVO):void
		{
			for each (var clazz:ClassVO in pkg.classes)
			{
				imports[clazz.name] = clazz.packageName.split(".");
			}
		}

	}
}